package models.application;

import java.util.*;

import javax.persistence.*;

import com.avaje.ebean.*;
import com.avaje.ebean.Query;
import models.pubobj.*;
import models.user.*;

import play.db.ebean.*;
import utils.AniMapBuilder;
import utils.MVCUtils;

@Entity
public class AniApp extends Model {

	@Id
	public Long id;
	
	@ManyToOne
	public AniUser ownerUser;
	
	@ManyToOne
	public AniApp relyOn;

	@ManyToOne
	public AniAppClassification appClassification;

	//generate automatically
	public String token;
	
	@ManyToOne
	public AniObjectType type;
	
	@ManyToOne
	public AniObjectState state;

	public String appName;

    public String description;

    public String forwardUrl;
	
	public byte[] icon;

    public AniApp(Long id,
                  AniUser ownerUser,
                  Long relyOnAppId,
                  Long appClassificationId,
                  String token,
                  Long typeId,
                  AniObjectState state,
                  String appName,
                  String description,
                  String forwardUrl
    ) {
        this.id = id;
        this.ownerUser = ownerUser;
        this.relyOn = (relyOnAppId != null && relyOnAppId > 0) ? new AniApp(relyOnAppId) : null;
        this.appClassification = new AniAppClassification(appClassificationId);
        this.token = token;
        this.type = new AniObjectType(typeId);
        this.state = state;
        this.appName = appName;
        this.description = description;
        this.forwardUrl = forwardUrl;
    }

    public AniApp(AniUser ownerUser,
                  Long relyOnAppId,
                  Long appClassificationId,
                  String token,
                  Long typeId,
                  AniObjectState state,
                  String appName,
                  String description,
                  String forwardUrl) {
        this.ownerUser = ownerUser;
        this.relyOn = (relyOnAppId != null && relyOnAppId > 0) ? new AniApp(relyOnAppId) : null;
        this.appClassification = new AniAppClassification(appClassificationId);
        this.token = token;
        this.type = new AniObjectType(typeId);
        this.state = state;
        this.appName = appName;
        this.description = description;
        this.forwardUrl = forwardUrl;
    }

    public AniApp(Long id) {
        this.id = id;
    }

    public static Model.Finder<Long, AniApp> find = new Model.Finder(Long.class, AniApp.class);

    public static Query<AniApp> finder(){
        return find
                .fetch("ownerUser")
                .fetch("state")
                .fetch("relyOn")
                .fetch("appClassification")
                .fetch("type");
    }
	
	public static List<AniApp> findAll() {
        return find.all();
    }

    public static AniApp findByAppId(Long appId){
        AniObjectState retiredState = AniObjectState.findByStateKey(
                AniObjectState.States.RETIRED.name()
        );
        return finder()
                .where()
                .idEq(appId)
                .ne("state", retiredState)
                .findUnique();
    }

    public static AniApp findByAppName(String appName) {
        return finder()
                .where()
                .eq("appName", appName)
                .ne("state", AniObjectState.findByStateKey(AniObjectState.States.RETIRED.name()))
                .findUnique();
    }
    
    public static List<AniApp> findByOwnerEmail(String email){
    	return finder()
                .where()
    			.eq("ownerUser.email", email)
    			.orderBy()
    			.desc("id")
    			.findList();
    }

    public static Integer findAppsCountWithId(List<Long> appIds){
        return finder()
                .where()
                .idIn(appIds)
                .eq("state", AniObjectState.findByStateKey(AniObjectState.States.ACTIVATED.name()))
                .findRowCount();
    }

    // --query
    public static List<AniApp> queryPublicApps(Map<String, Object> queryElements, String queryKeyword, Integer page){
        AniMapBuilder<String, Object> subQueryElements = new AniMapBuilder<String, Object>();
        subQueryElements
                .put("type.id", AniObjectType.findByTypeKey(models.pubobj.AniObjectType.ObjectTypes.PUBLIC.name()).id)
                .put("state.id", AniObjectState.findByStateKey(AniObjectState.States.ACTIVATED.name()).id);
        queryElements.putAll(subQueryElements.getMap());
        return finder()
                .where()
                .allEq(queryElements)
                .or(
                        find.getExpressionFactory().like("appName", "%" + queryKeyword + "%"),
                        find.getExpressionFactory().like("description", "%" + queryKeyword + "%")
                )
                .findPagingList(Integer.parseInt(MVCUtils.getConfig("wd.page.size")))
                .getPage(page)
                .getList();
    }

    public static List<AniApp> queryUserOwnedApp(Map<String, Object> queryElements, String queryKeyword, AniUser curUser, Integer page){
        queryElements.put("ownerUser.id", curUser.id);
        System.out.println(queryElements);
        return finder()
                .where()
                .allEq(queryElements)
                .or(
                        find.getExpressionFactory().like("appName", "%" + queryKeyword + "%"),
                        find.getExpressionFactory().like("description", "%" + queryKeyword + "%")
                )
                .findPagingList(Integer.parseInt(MVCUtils.getConfig("wd.page.size")))
                .getPage(page)
                .getList();
    }
    public static Integer queryUserOwnedAppTotalSize(Map<String, Object> queryElements, String queryKeyword, AniUser curUser){
        queryElements.put("ownerUser.id", curUser.id);
        return finder()
                .where()
                .allEq(queryElements)
                .or(
                        find.getExpressionFactory().like("appName", "%" + queryKeyword + "%"),
                        find.getExpressionFactory().like("description", "%" + queryKeyword + "%")
                ).findRowCount();
    }

    public static Integer findByStateCount(List<Long> appsIdList, AniObjectState targetState){
        return finder()
                .where()
                .idIn(appsIdList)
                .eq("state.id", targetState.id)
                .findRowCount();
    }

}
